package org.lanyu.springainovel.common.config;

import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

/**
 * 自定义认证提供者
 * 使用自定义密码编码器进行密码验证
 */
@Component
public class CustomDaoAuthenticationProvider extends DaoAuthenticationProvider {

    public CustomDaoAuthenticationProvider(UserDetailsService userDetailsService, CustomPasswordEncoder passwordEncoder) {
        setUserDetailsService(userDetailsService);
        setPasswordEncoder(passwordEncoder);
    }

    /**
     * 重写密码验证方法，使用用户名作为盐值
     */
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails,
            UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        
        if (authentication.getCredentials() == null) {
            this.logger.debug("Failed to authenticate since no credentials provided");
            System.out.println("认证失败：没有提供凭据");
            throw new BadCredentialsException(this.messages
                    .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
        
        String presentedPassword = authentication.getCredentials().toString();
        CustomPasswordEncoder customPasswordEncoder = (CustomPasswordEncoder) this.getPasswordEncoder();
        
        // 使用用户名作为盐值验证密码
        // 注意：matchesWithUsernameSalt方法的参数顺序是(明文密码, 加密密码, 用户名)
        boolean isMatch = customPasswordEncoder.matchesWithUsernameSalt(presentedPassword, userDetails.getPassword(), userDetails.getUsername());
        
        if (!isMatch) {
            this.logger.debug("Failed to authenticate since password does not match stored value");
            throw new BadCredentialsException(this.messages
                    .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
        
        System.out.println("=== CustomDaoAuthenticationProvider.additionalAuthenticationChecks 成功 ===");
    }
}